/*
*	Created:			15.06.10
*	Author:				009
*	Last Modifed:		-
*/

#include "os.h"
#include "main.h"

// server versions defines
#define SAMP_VERSION_032			1
// server address defines
#ifdef WIN32
	// R2
	#define R2_CALL_FROM_THREAD		0x497B76
	#define R2_CALL_NOP_THREAD		0x497B98
	#define R2_TICK_RATE			0x4E0794
#else
	// R2
	#define R2_CALL_FROM_THREAD		0x807771D
	#define R2_CALL_NOP_THREAD		0x807772F
	#define R2_TICK_RATE			0x81778A4
#endif

#ifndef PAGESIZE
	#define PAGESIZE (4096)
#endif

MUTEX_IDENTIFY(MultiThreadMutex);
int TickRate = 5;

// call hook func
bool Unlock(void *address, int len)
{
	#ifdef WIN32
		DWORD
			oldp;
		// Shut up the warnings :D
		return !!VirtualProtect(address, len, PAGE_EXECUTE_READWRITE, &oldp);
	#else
		return !mprotect((void*)(((int)address / PAGESIZE) * PAGESIZE), PAGESIZE, PROT_WRITE | PROT_READ | PROT_EXEC);
	#endif
}

void CallHook(DWORD from, DWORD to) 
{
	if(Unlock((void*)from,5))
	{
		DWORD disp = to - (from + 5);
		*(BYTE *)(from) = 0xE8;
		*(DWORD *)(from + 1) = (DWORD)disp;
	}
}

void SAMP_ThreadComplete()
{
	// free mutex
	MUTEX_EXIT(MultiThreadMutex);
	// sleep
	SLEEP(TickRate);
	// close mutex
	MUTEX_ENTER(MultiThreadMutex);
}

// multithread init
void MultiThreadInit(int ServerVersion)
{
	// create mutex
	CREATE_MUTEX(MultiThreadMutex);
	// set hook
	switch(ServerVersion)
	{
	case SAMP_VERSION_032:
		{
			CallHook(R2_CALL_FROM_THREAD,(DWORD)SAMP_ThreadComplete);
			for(int i = R2_CALL_FROM_THREAD + 5;i < R2_CALL_NOP_THREAD;i++) *(BYTE*)(i) = 0x90;
			TickRate = *(DWORD*)(R2_TICK_RATE);
			break;
		}
	}
}
